#pragma once

#include <vector>
#include <memory>
#include <map>
//#include <glog/logging.h>
#include <opencv2/core.hpp>

#include "ImageShow/Shapes.h"
//#pragma comment(lib,"C:/google-glog/lib/glog.lib")

namespace CvImageShow {
	namespace Shapes {

		class CV_EXPORT ShapeRegistry
		{
		public:
			typedef std::shared_ptr<CShape >(*Creator)(const ShapeDef&);
			typedef std::map<std::string, Creator> CreatorRegistry;

			static CreatorRegistry& Registry()
			{
				static CreatorRegistry* g_registry_ = new CreatorRegistry();
				return *g_registry_;
			}

			static void AddCreator(const std::string& type, Creator creator)
			{
				CreatorRegistry& registry = Registry();
				//				CHECK_EQ(registry.count(type), 0) << "Shape type " << type << "already registered.";
				registry[type] = creator;
			}

			static std::shared_ptr<CShape > CreateShape(const ShapeDef& shapeDef)
			{
				const std::string& type = shapeDef.type;
				CreatorRegistry& registry = Registry();
				registry.count(type);
				//CHECK_EQ(registry.count(type), 1) << "Unknown shape type: " << type
				//	<< " (known types: " << ShapeTypeListString() << ")";

				return registry[type](shapeDef);
			}

			static std::vector<std::string> ShapeTypeList()
			{
				CreatorRegistry& registry = Registry();
				std::vector<std::string> shape_types;
				for (/*typename*/ CreatorRegistry::iterator iter = registry.begin();
					iter != registry.end(); ++iter)
				{
					shape_types.push_back(iter->first);
				}
				return shape_types;
			}
			static std::string ShapeTypeListString()
			{
				std::vector<std::string> shape_types = ShapeTypeList();
				std::string shape_types_str;
				for (std::vector<std::string>::iterator iter = shape_types.begin();
					iter != shape_types.end(); ++iter)
				{
					if (iter != shape_types.begin())
					{
						shape_types_str += ", ";
					}
					shape_types_str += *iter;
				}
				return shape_types_str;
			}
		private:
			ShapeRegistry() { ; }
		};

		class CV_EXPORT ShapeRegisterer
		{
		public:
			ShapeRegisterer(const std::string& type,
				std::shared_ptr<CShape >(*creator)(const ShapeDef&))
			{
				ShapeRegistry::AddCreator(type, (ShapeRegistry::Creator)creator);
			}
		};
	#define REGISTER_SHAPE_CREATOR(type, creator)					\
		static ShapeRegisterer g_creator_##type(#type, creator);	\

	#define REGISTER_SHAPE_CLASS(type)											\
		std::shared_ptr<CShape> Creator_##type##Shape(const ShapeDef& param)	\
		{																	\
			return std::shared_ptr<CShape>(new CShape##type(param));		\
		}																	\
		REGISTER_SHAPE_CREATOR(type, Creator_##type##Shape)

	}	// end for namespace Shapes
}	// end for namespace CvImageShow

